home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
mtask.exe
/
MTASK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-09
|
6KB
|
337 lines
/* MTASK V1.0
A minimal multitasking library for DOS. Copyright 1993 I H Ting.
Disclaimer:
Use the code at your own peril. I don't promise it actually does anything.
Even if the world ends when you use it, don't hold me responsible.
Comments and suggestions, however, are welcomed. I can be reached at:
Compuserve ID: 100023,3363
Internet: cm1826@ccub.wlv.ac.uk
*/
#include "stdio.h"
#include "dos.h"
#include "stdlib.h"
#include "conio.h"
#include "mtask.h"
enum TaskStatus {INVALID, CURRENT, READY, WAITING};
typedef struct {
unsigned bp;
unsigned di;
unsigned si;
unsigned ds;
unsigned es;
unsigned dx;
unsigned cx;
unsigned bx;
unsigned ax;
unsigned ip;
unsigned cs;
unsigned flags;
} RegsOnStack;
typedef struct {
unsigned sp;
unsigned ss;
enum TaskStatus status;
unsigned *semaphore;
void *pOwnStack;
} TaskInfo;
TaskInfo taskList[MAX_TASKS];
void interrupt TheScheduler(void);
void interrupt ChangeTask(void);
void interrupt (*PrevInterrupt)(void);
void WakeUpTasks(unsigned *semaphore);
void EndMultiTasking(void);
void TidyUp(void);
int IsDeadLock(void);
static unsigned originalSS, originalSP;
static unsigned IOsemaphore=0;
static int currentTaskID = 0;
static char bMultiTasking = 1;
static void interrupt TheScheduler(void)
{
(*PrevInterrupt)();
taskList[currentTaskID].ss = _SS;
taskList[currentTaskID].sp = _SP;
if(taskList[currentTaskID].status==CURRENT)
taskList[currentTaskID].status = READY;
if(IsDeadLock()) bMultiTasking = 0;
if(!bMultiTasking) { /* stop bMultiTasking */
disable();
_SS = originalSS;
_SP = originalSP;
setvect(8, PrevInterrupt);
TidyUp();
enable();
return;
}
do{
currentTaskID++;
if(currentTaskID==MAX_TASKS) currentTaskID = 0;
}while(taskList[currentTaskID].status!=READY);
_SS = taskList[currentTaskID].ss;
_SP = taskList[currentTaskID].sp;
taskList[currentTaskID].status = CURRENT;
}
static void interrupt ChangeTask(void)
{
disable();
taskList[currentTaskID].ss = _SS;
taskList[currentTaskID].sp = _SP;
if(taskList[currentTaskID].status==CURRENT)
taskList[currentTaskID].status = READY;
if(IsDeadLock()) bMultiTasking = 0;
if(!bMultiTasking) {
disable();
_SS = originalSS;
_SP = originalSP;
setvect(8, PrevInterrupt);
TidyUp();
enable();
return;
}
/* find new pTaskFunc */
do{
currentTaskID++;
if(currentTaskID==MAX_TASKS) currentTaskID = 0;
}while(taskList[currentTaskID].status!=READY);
_SS = taskList[currentTaskID].ss;
_SP = taskList[currentTaskID].sp;
taskList[currentTaskID].status = CURRENT;
enable();
}
static int IsDeadLock(void)
{
register int i;
for(i=0; i<MAX_TASKS; i++)
if(taskList[i].status==READY) return 0;
return 1;
}
static void TidyUp(void)
{
int i;
for(i=0; i<MAX_TASKS; i++) {
if(taskList[i].pOwnStack) {
free(taskList[i].pOwnStack);
taskList[i].pOwnStack = NULL;
}
}
}
int AddNewTask(PTaskFunc pTaskFunc)
{
RegsOnStack *pRegs;
unsigned taskID, i;
void *pNewStack;
disable();
taskID = MAX_TASKS;
for(i=0; i<MAX_TASKS; i++)
if (taskList[i].status == INVALID){
taskID = i;
break;
}
if (taskID == MAX_TASKS){ /* Failed */
enable();
return taskID;
}
pNewStack = malloc(TASK_STACK_SIZE + sizeof(RegsOnStack));
if (pNewStack==NULL) return MAX_TASKS;
taskList[taskID].pOwnStack = pNewStack;
pRegs = (RegsOnStack *) taskList[taskID].pOwnStack +
TASK_STACK_SIZE - sizeof(RegsOnStack);
taskList[taskID].sp = FP_OFF((RegsOnStack far *) pRegs);
taskList[taskID].ss = FP_SEG((RegsOnStack far *) pRegs);
pRegs->cs = FP_SEG(pTaskFunc);
pRegs->ip = FP_OFF(pTaskFunc);
pRegs->ds = _DS;
pRegs->es = _DS;
pRegs->flags = 0x200;
taskList[taskID].status = READY;
enable();
return taskID;
}
void interrupt StartMultiTasking(void)
{
disable();
PrevInterrupt = getvect(8);
setvect(8, TheScheduler);
originalSS = _SS;
originalSP = _SP;
_SS = taskList[currentTaskID].ss;
_SP = taskList[currentTaskID].sp;
enable();
}
void RemoveTask(unsigned taskID)
{
disable();
if(taskID <MAX_TASKS){
taskList[taskID].status = INVALID;
if(taskList[taskID].pOwnStack)
free(taskList[taskID].pOwnStack);
taskList[taskID].pOwnStack = NULL;
}
enable();
ChangeTask();
}
void InitMultiTasking(void)
{
int i;
for(i=0; i<MAX_TASKS; i++) {
taskList[i].status = INVALID;
taskList[i].semaphore = NULL;
taskList[i].pOwnStack = NULL;
}
}
void EndMultiTasking(void)
{
bMultiTasking = 0;
ChangeTask();
}
void MTWait(unsigned *semaphore)
{
disable();
while(*semaphore) {
taskList[currentTaskID].status = WAITING;
taskList[currentTaskID].semaphore = semaphore;
ChangeTask();
disable();
}
*semaphore = 1;
enable();
}
void MTSignal(unsigned *semaphore)
{
disable();
taskList[currentTaskID].semaphore = NULL;
*semaphore = 0;
WakeUpTasks(semaphore);
ChangeTask();
enable();
}
static void WakeUpTasks(unsigned *semaphore)
{
int i;
for(i=0; i<MAX_TASKS; i++)
if(taskList[i].semaphore == semaphore) {
taskList[i].semaphore = NULL;
if(taskList[i].status == WAITING)
taskList[i].status = READY;
return;
}
}
void MTPuts(char *s)
{
MTWait(&IOsemaphore);
puts(s);
MTSignal(&IOsemaphore);
}
void MTXYPuts(int x,int y,char *s)
{
MTWait(&IOsemaphore);
gotoxy(x,y);
cputs(s);
MTSignal(&IOsemaphore);
}
char MTGetch(void)
{
char ch;
MTWait(&IOsemaphore);
if (kbhit()) ch = getch();
else ch = 0;
MTSignal(&IOsemaphore);
return ch;
}
void MTPutch(char c)
{
MTWait(&IOsemaphore);
putch(c);
MTSignal(&IOsemaphore);
}
void MTXYPutch(int x, int y, char c)
{
MTWait(&IOsemaphore);
gotoxy(x,y);
putch(c);
MTSignal(&IOsemaphore);
}